package com.common.util.sevenz;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.List;


/**
 * 使用命令行方式调用windows版和linux版二进制7z程序实现压缩解压缩，命令行见/resources/bin/**
 *
 * @author
 * @date
 */
@Slf4j(topic = "SevenZipCommand")
public class SevenZipCommand {
    static String charset = "utf8";

    /**
     * 获取命令执行路径
     *
     * @return String
     * @throws IOException
     */
    public static String getBinPath() throws IOException {
        // 运行系统
        String strOS = System.getProperty("os.name").toLowerCase();
        // 执行路径
        String binDir = System.getProperty("java.io.tmpdir") + "/7zbin/";
        new File(binDir).mkdirs();

        String binPath = "";
        if (strOS.indexOf("win") != -1) {
            // windows系统
            charset = "gbk";
            File bin = new File(binDir + "7za.exe");
            if (!bin.exists()) {
                Files.copy(SevenZipCommand.class.getResourceAsStream("/bin/win/7za.exe"), bin.toPath());
            }
            binPath = bin.getAbsolutePath();
        }
        if (strOS.indexOf("linux") != -1) {
            charset = "utf8";
            // 主执行文件放最后
            String[] files = {"7z.so", "7z"};
            for (String file : files) {
                File bin = new File(binDir + file);
                if (!bin.exists()) {
                    Files.copy(SevenZipCommand.class.getResourceAsStream("/bin/linux/" + file), bin.toPath());
                    if (!bin.canExecute()) {
                        bin.setExecutable(true);
                    }
                }
                binPath = bin.getAbsolutePath();
            }
        }
        return binPath;
    }

    /**
     * 压缩
     *
     * @param archiveName 7z压缩包文件
     * @param fileName    待压缩文件
     * @param options     执行参数
     * @return boolean
     */
    public static boolean compress(String archiveName, String fileName, String... options) {
        boolean ok = false;
        try {
            File archiveFile = new File(archiveName);
            if (archiveFile.exists()) {
                archiveFile.delete();
            }

            List<String> commend = new java.util.ArrayList<String>();
            commend.add(getBinPath());
            commend.add("a");
            commend.add("-y");
            commend.add(archiveName);
            commend.add(fileName);
            for (String option : options) {
                commend.add(option);
            }

            ProcessBuilder builder = new ProcessBuilder();
            log.info(JSON.toJSONString(commend));
            builder.command(commend);
            builder.redirectErrorStream(true);
            Process p = builder.start();
            p.getOutputStream().close();
            BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName(charset)));
            String tmp = null;
            StringBuffer sb = new StringBuffer();
            while ((tmp = br.readLine()) != null) {
                sb.append(tmp);
            }
            int exitValue = p.waitFor();
            log.info(sb.toString());
            if (sb.toString().indexOf("Everything is Ok") != -1) {
                ok = true;
            }
        } catch (Exception e) {
            log.error("压缩出错", e);
        }

        return ok;
    }

    /**
     * 解压
     *
     * @param archiveName 7z压缩包文件
     * @param outputDir   解压的目录
     * @param options     执行参数
     * @return boolean
     */
    public static boolean decompress(String archiveName, String outputDir, String... options) {
        boolean ok = false;
        try {
            new File(outputDir).mkdirs();

            List<String> commend = new java.util.ArrayList<String>();
            commend.add(getBinPath());
            commend.add("x");
            commend.add("-y");
            commend.add(archiveName);
            commend.add("-o" + outputDir);
            for (String option : options) {
                commend.add(option);
            }

            ProcessBuilder builder = new ProcessBuilder();
            log.info(JSON.toJSONString(commend));
            builder.command(commend);
            builder.redirectErrorStream(true);
            Process p = builder.start();
            p.getOutputStream().close();
            BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("utf8")));
            String tmp = null;
            StringBuffer sb = new StringBuffer();
            while ((tmp = br.readLine()) != null) {
                sb.append(tmp);
            }
            int exitValue = p.waitFor();
            log.info(sb.toString());
            if (sb.toString().indexOf("Everything is Ok") != -1) {
                ok = true;
            }
        } catch (Exception e) {
            log.error("解压出错", e);
        }
        return ok;
    }

    /**
     * 是否加密
     *
     * @param archiveName 7z压缩包文件
     * @return boolean
     */
    public static boolean isEncrypted(String archiveName) {
        boolean ok = false;
        try {
            List<String> commend = new java.util.ArrayList<String>();
            commend.add(getBinPath());
            commend.add("l");
            commend.add("-slt");
            commend.add(archiveName);

            ProcessBuilder builder = new ProcessBuilder();
            log.info(JSON.toJSONString(commend));
            builder.command(commend);
            builder.redirectErrorStream(true);
            Process p = builder.start();
            p.getOutputStream().close();
            BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("utf8")));
            String tmp = null;
            StringBuffer sb = new StringBuffer();
            while ((tmp = br.readLine()) != null) {
                sb.append(tmp);
            }
            int exitValue = p.waitFor();
            log.info(sb.toString());
            if (sb.toString().indexOf("Can not open encrypted archive") != -1) {
                ok = true;
            }
        } catch (Exception e) {
            log.error("加密出错", e);
        }
        return ok;
    }

    /**
     * <p>main.</p>
     *
     * @param args an array of {@link String} objects.
     * @throws IOException if any.
     */
    public static void main(String[] args) throws IOException {
        /*boolean compress = compress("F:\\开发工具\\hugo\\test.7z", "F:\\开发工具\\hugo\\test");
        log.info("" + compress);
        boolean isEncrypted = isEncrypted("F:\\开发工具\\hugo\\test.7z");
        log.info("" + isEncrypted);*/
        boolean decompress = decompress("F:\\开发工具\\hugo\\test.7z", "F:\\开发工具\\hugo\\test", "-pa");
        log.info("" + decompress);
    }
}
